import argparse
import os
import shutil
import time
import math
import random
import itertools

import torch
import torch.nn as nn
import torch.nn.parallel
import torch.backends.cudnn as cudnn
import torch.distributed as dist
import torch.optim
import torch.utils.data
import torch.utils.data.distributed
import torchvision.transforms as transforms
import torchvision.datasets as datasets
import torchvision.models as models

import numpy as np

try:
    from nvidia.dali.plugin.pytorch import DALIGenericIterator
    from nvidia.dali.pipeline import Pipeline
    import nvidia.dali.types as types
#     import nvidia.dali.ops as ops
    import nvidia.dali.fn as fn
except ImportError:
    raise ImportError("Please install DALI from https://www.github.com/NVIDIA/DALI to run this example.")

def create_dali_pipeline(file_list,
                         # file_root,
                         batch_size,
                         resize_x,
                         resize_y,
                         stride,
                         sequence_length,
                         num_threads,
                         device_id,
                         crop_target_size,
                         is_training=False,
                         num_shards=1,
                         shard_id=0,):
    
    pipeline = Pipeline(batch_size, num_threads, device_id, seed=12 + device_id)
    with pipeline:
        images, labels = fn.readers.video_resize(
            device="gpu",
            # file_root=file_root,
            file_list=file_list,
            sequence_length=sequence_length,
            resize_x=resize_x,
            resize_y=resize_y,
            stride=stride,
            step=16*stride,
            num_shards=num_shards,
            shard_id=shard_id,
            random_shuffle=is_training,
            skip_vfr_check=True)
        if is_training:
            mirror = fn.random.coin_flip(probability=0.5)
            crop_pos_x = random.uniform(0.,1.)
            crop_pos_y = random.uniform(0.,1.)
        else:
            mirror = False
            crop_pos_x = 0.5
            crop_pos_y = 0.5
        images = fn.crop_mirror_normalize(
            images,
            dtype=types.FLOAT,
            output_layout="CFHW",
            crop_h=crop_target_size,
            crop_w=crop_target_size,
            crop_pos_x=crop_pos_x,
            crop_pos_y=crop_pos_y,
            mean=[0.485 * 255,0.456 * 255,0.406 * 255],
            std=[0.229 * 255,0.224 * 255,0.225 * 255],
            mirror=mirror)
        # labels = fn.cast(labels, device="gpu", dtype=types.DALIDataType.INT64)
        labels = labels.gpu()
        pipeline.set_outputs(images, labels)
    return pipeline

# class VideoPipe(Pipeline):
#     def __init__(self,
#                  file_list,
#                  # file_root,
#                  batch_size,
#                  resize_x,
#                  resize_y,
#                  stride,
#                  sequence_length,
#                  num_threads,
#                  device_id,
#                  crop_target_size,
#                  is_training=False,
#                  num_shards=1,
#                  shard_id=0):
#         super(VideoPipe, self).__init__(batch_size, num_threads, device_id)
#         self.input = ops.VideoReader(
#             device="gpu",
#             file_list=file_list,
#             sequence_length=sequence_length,
#             num_shards=num_shards,
#             shard_id=shard_id,
#             random_shuffle=is_training,
# #             resize_x=resize_x,
# #             resize_y=resize_y,
#             stride=stride,
#             step=-1,)
#         self.resize = ops.Resize(
#             device="gpu",
#             resize_x=resize_x,
#             resize_y=resize_y)
#         if is_training:
#             mirror = random.choice([0, 1])
#             crop_pos_x = random.uniform(0.,0.2)
#             crop_pos_y = random.uniform(0.,0.2)
#         else:
#             mirror = 0
#             crop_pos_x = 0.0625
#             crop_pos_y = 0.17
#         self.crop_mirror_norm = ops.CropMirrorNormalize(
#             device="gpu",
#             output_layout="CFHW",
#             mirror=mirror,
#             crop_pos_x=crop_pos_x,
#             crop_pos_y=crop_pos_y,
#             crop=[crop_target_size, crop_target_size],
#             mean=[0.485 * 255,0.456 * 255,0.406 * 255],
#             std=[0.229 * 255,0.224 * 255,0.225 * 255])
        
# #         self.cast_label = ops.Cast(device="gpu", dtype=types.DALIDataType.INT64)

#     def define_graph(self):
#         output, label = self.input(name="Reader")
#         output = self.resize(output)
#         output = self.crop_mirror_norm(output)

# #         label = self.cast_label(label)
#         return output, label